package com.dheaven.framework.core.dwrmvc;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.directwebremoting.spring.SpringConfigurator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.util.StringUtils;

public class SharedCode {

	protected static final Log log = LogFactory.getLog(SharedCode.class);

	public static String resolveBeanClassname(BeanDefinition definition, BeanDefinitionRegistry registry) {
		String beanClassName = definition.getBeanClassName();
		if (!StringUtils.hasText(beanClassName)) {
			while (definition instanceof ChildBeanDefinition) {
				String parentName = ((ChildBeanDefinition) definition).getParentName();
				BeanDefinition parentDefinition = findParentDefinition(parentName, registry);
				if (parentDefinition == null) {
					if (log.isDebugEnabled()) {
						log.debug("No parent bean named '" + parentName + "' could be found in the " + "hierarchy of BeanFactorys. Check you've defined a bean called '" + parentName + "'");
					}
					break;
				}
				beanClassName = parentDefinition.getBeanClassName();
				if (StringUtils.hasText(beanClassName)) {
					// found the class name we were looking for
					break;
				}
				definition = parentDefinition;
			}
		}

		return beanClassName;
	}

	private static BeanDefinition findParentDefinition(String parentName, BeanDefinitionRegistry registry) {
		if (registry != null) {
			if (registry.containsBeanDefinition(parentName)) {
				return registry.getBeanDefinition(parentName);
			} else if (registry instanceof HierarchicalBeanFactory) {
				// Try to get parent definition from the parent BeanFactory.
				// This could return null
				BeanFactory parentBeanFactory = ((HierarchicalBeanFactory) registry).getParentBeanFactory();
				return findParentDefinition(parentName, (BeanDefinitionRegistry) parentBeanFactory);
			}
		}

		// we've exhausted all possibilities
		return null;
	}

	@SuppressWarnings("unchecked")
	public static Map<String, RuntimeBeanReference> lookupCreators(BeanDefinitionRegistry registry) {
		BeanDefinition config = registerSpringConfiguratorIfNecessary(registry);
		return (Map<String, RuntimeBeanReference>) config.getPropertyValues().getPropertyValue("creators").getValue();
	}

	protected static BeanDefinition registerSpringConfiguratorIfNecessary(BeanDefinitionRegistry registry) {
		if (!registry.containsBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID)) {
			BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SpringConfigurator.class);
			builder.addPropertyValue("creators", new ManagedMap());
			builder.addPropertyValue("converters", new ManagedMap());
			registry.registerBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID, builder.getBeanDefinition());
		}
		return registry.getBeanDefinition(DEFAULT_SPRING_CONFIGURATOR_ID);
	}

	protected static final String DEFAULT_SPRING_CONFIGURATOR_ID = "__dwrConfiguration";

}
